/*
 * Copyright 2012 xbogar.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cz.muni.fi.pa165.musiclibraryrestserver;

/**
 *
 * @author xbogar
 */
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import cz.muni.fi.PA165.musiclibraryapi.dto.AuthorDTOInterface;
import cz.muni.fi.PA165.musiclibraryapi.dto.GenreDTOInterface;
import cz.muni.fi.PA165.musiclibraryapi.services.AuthorService;
import cz.muni.fi.PA165.musiclibraryapi.services.GenreService;
import cz.muni.fi.PA165.musiclibrarybackend.dto.AuthorDTO;
import cz.muni.fi.PA165.musiclibrarybackend.dto.GenreDTO;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.TransactionSystemException;
 
@WebServlet(urlPatterns = "/*")
public class RestServlet extends HttpServlet {
    
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    AuthorService authorService = context.getBean(AuthorService.class);
    GenreService genreService = context.getBean(GenreService.class);
 
    final List<Map<String, String>> zaznamy = Collections.synchronizedList(new ArrayList<Map<String, String>>());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String pathInfo = request.getPathInfo();
        if (pathInfo != null && pathInfo.matches("/\\d+")) {
            response.setContentType("application/bjson");
            ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(response.getOutputStream(), zaznamy.get(Integer.parseInt(pathInfo.substring(1))));
        } else {
            if ("html".equals(request.getParameter("type"))) {
                response.setContentType("text/html;charset=utf-8");
                PrintWriter out = response.getWriter();
                response.setHeader("Refresh", "5");
                out.println("<h1>REST server log " + request.getContextPath() + "</h1>");
//                out.println("<table border=\"1\">");
                synchronized (zaznamy) {
                    for (int i = zaznamy.size(); --i >= 0;) {
                        Map<String, String> m = zaznamy.get(i);
                        out.println(i);
                    }
                }
                out.println("</table>");
            } else {
                response.setContentType("application/json");
                ObjectMapper mapper = new ObjectMapper();
                mapper.writeValue(response.getOutputStream(), zaznamy);
            }
        }
    }
 
    @Override
    protected synchronized void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        if (request.getContentType().startsWith("application/json")) {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonNode = mapper.readValue(request.getInputStream(), JsonNode.class);
            JsonNode genreCreate = jsonNode.get("genrecreate");
            JsonNode genreUpdate = jsonNode.get("genreupdate");
            JsonNode genreDelete = jsonNode.get("genredelete");
            JsonNode genreGetAll = jsonNode.get("genregetall");
            
            JsonNode authorCreate = jsonNode.get("authorcreate");
            JsonNode authorUpdate = jsonNode.get("authorupdate");
            JsonNode authorDelete = jsonNode.get("authordelete");
            JsonNode authorGetAll = jsonNode.get("authorgetall");
            
            if (!jsonNode.isMissingNode()) {
                Map<String, String> m = new LinkedHashMap<String, String>();
                if(authorCreate!=null && authorCreate.textValue() != null){
                    m.put("autor created", authorCreate.textValue());
                    AuthorDTO authorDTO = new AuthorDTO();
                    authorDTO.setName(authorCreate.textValue());
                    authorService.createAuthor(authorDTO);
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(authorDelete!=null && authorDelete.textValue()!=null){
                    long authorID;
                    try{
                        authorID = Long.parseLong(authorDelete.textValue());
                    } catch(NumberFormatException e){
                        m.put("error", "Author id should be long type");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    AuthorDTOInterface adelete=null;
                    try{
                        adelete = authorService.getAuthor(authorID);
                        authorService.deleteAuthor(adelete);
                    } catch(TransactionSystemException e){
                        m.put("error", "Author "+adelete.getName()+" is still used by some song");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    } catch(IllegalArgumentException e){
                        m.put("error", "Author with id "+ authorID+" does not exist.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    m.put("author deleted", authorDelete.textValue());
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(authorUpdate!=null && authorUpdate.textValue()!=null){
                    String[] split = authorUpdate.textValue().split(":");
                    if(split.length != 2){
                        m.put("error", "Illegal argumets.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    long authorID;
                    try{
                        authorID = Long.parseLong(split[0]);
                    } catch(NumberFormatException e){
                        m.put("error", "Author id should be long type");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    AuthorDTOInterface aToUpdate = null;
                    try{
                        aToUpdate = authorService.getAuthor(authorID);
                    } catch(IllegalArgumentException e){
                        m.put("error", "Author with id "+ authorID+"does not exist.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    if(aToUpdate==null){
                        m.put("error", "Author with id "+ authorID+" does not exist.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    aToUpdate.setName(split[1]);
                    authorService.updateAuthor(aToUpdate);
                    m.put("author updated", split[1]);
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(authorGetAll!=null && authorGetAll.textValue()!=null){
                    List<AuthorDTOInterface> allAuthors = authorService.getAllAuthors();
                    m.put("all authors", "id, name");
                    for(AuthorDTOInterface a: allAuthors){
                        m.put(String.valueOf(a.getId()),a.getName());
                    }
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(genreCreate!=null && genreCreate.textValue() != null){
                    m.put("genre created", genreCreate.textValue());
                    GenreDTO gdto = new GenreDTO();
                    gdto.setName(genreCreate.textValue());
                    genreService.createGenre(gdto);
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(genreDelete!=null && genreDelete.textValue()!=null){
                    long genreID;
                    try{
                        genreID = Long.parseLong(genreDelete.textValue());
                    } catch(NumberFormatException e){
                        m.put("error", "Genre id should be long type");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    GenreDTOInterface gdelete = null;
                    try{
                        gdelete = genreService.getGenre(genreID);
                        genreService.deleteGenre(gdelete);
                    } catch (TransactionSystemException e) {
                        m.put("genre delete error", "Genre "+gdelete.getName()+" is still used in song.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    } catch (IllegalArgumentException e){
                        m.put("error", "Genre with id "+ genreID + " does not exist.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    m.put("genre deleted", genreDelete.textValue());
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(genreUpdate!=null && genreUpdate.textValue()!=null){
                    String[] split = genreUpdate.textValue().split(":");
                    if(split.length != 2){
                        m.put("error", "Illegal argumets.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                    }
                    long genreID;
                    try{
                        genreID = Long.parseLong(split[0]);
                    } catch(NumberFormatException e){
                        m.put("error", "Genre id should be long type");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    GenreDTOInterface gToUpdate = null;
                    try{
                        gToUpdate = genreService.getGenre(genreID);
                    } catch (IllegalArgumentException e){
                        m.put("error", "Genre with id " + genreID + " does not exist.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    if(gToUpdate==null){
                        m.put("error", "Genre with id "+ genreID + " does not exist.");
                        zaznamy.add(m);
                        response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                        return;
                    }
                    gToUpdate.setName(split[1]);
                    genreService.updateGenre(gToUpdate);
                    m.put("author updated", split[1]);
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                if(genreGetAll!=null && genreGetAll.textValue()!=null){
                    List<GenreDTOInterface> allGenres = genreService.getAllGenres();
                    m.put("all genres", "id, name");
                    for(GenreDTOInterface g: allGenres){
                        m.put(String.valueOf(g.getId()),g.getName());
                    }
                    zaznamy.add(m);
                    response.sendRedirect(request.getContextPath() + "/remote/" + (zaznamy.size() - 1));
                }
                
            } else {
                System.err.println("Missing key");
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing required data key.");
            }
        } else {
            System.err.println("Unknown request type " + request.getContentType());
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown request type.");
        }
    }
}